<html>
<head><meta charset="utf-8"><title>mem::forget, borrowed buffers and DMA · wg-async-foundations · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/index.html">wg-async-foundations</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html">mem::forget, borrowed buffers and DMA</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="243936503"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243936503" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243936503">(Jun 25 2021 at 16:06)</a>:</h4>
<p>The topic might seem just a random mix of words, but it summarizes a big problem while using DMA in embedded. And since DMA is pretty much the number one method of writing async code in embedded, I wanted to highlight this pain point here.</p>
<p>A good summary of the problem could be the blog from boats about io_uring. Which describes the problem safe rust has with completion based APIs. However, the solution described by boats isn't very fit for embedded, because most of the times alloc isn't an option.</p>
<p>A possible solution would be some kind of Leak auto trait, which has been discussed before but I wanted to bring it up again with a light in embedded async (and embedded DMA usage in general).</p>



<a name="243936670"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243936670" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243936670">(Jun 25 2021 at 16:07)</a>:</h4>
<p>The solution we have used for now is to mark the constructor of drivers unsafe with the safety requirement that the user must not leak any futures that borrows it. Which isn't hard in practice but it's a very contrived requirement</p>



<a name="243936850"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243936850" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243936850">(Jun 25 2021 at 16:09)</a>:</h4>
<p>And also prevents a fully safe API.</p>
<p>I would be curious to hear some opinions on the problem and possible solutions.</p>
<p>We also experimented with <code>&amp;'static mut</code> buffers, but they are very unergonomic and hard to work with due to the move semantics</p>



<a name="243936945"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243936945" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243936945">(Jun 25 2021 at 16:10)</a>:</h4>
<p>It also plays badly with traits, requiring full GATs, instead of just "lifetime GAT"</p>



<a name="243937052"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243937052" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243937052">(Jun 25 2021 at 16:10)</a>:</h4>
<p>To support both &amp;'static mut buffers and <code>Box</code>, etc</p>



<a name="243939428"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243939428" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nagisa <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243939428">(Jun 25 2021 at 16:30)</a>:</h4>
<p>Hm, I was going to say that cancelling DMA operation is an option in many cases, but then I realised it depends on the device on the other end.</p>



<a name="243939517"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243939517" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nagisa <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243939517">(Jun 25 2021 at 16:31)</a>:</h4>
<p>Or does it. You need to have some way to reset communication and abort a command you've been sending in order to correctly support situations where your firmware resets the mcu out of the blue (e.g. because of a crash of some sort).</p>



<a name="243940185"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243940185" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243940185">(Jun 25 2021 at 16:37)</a>:</h4>
<p>Cancelling the DMA itself isn't the problem, the problem is that you have to do that on drop, which isn't guaranteed to run</p>



<a name="243941026"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243941026" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243941026">(Jun 25 2021 at 16:45)</a>:</h4>
<p>The user can forger the transfer, which will clear the borrow on the buffer</p>



<a name="243943704"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243943704" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nagisa <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243943704">(Jun 25 2021 at 17:07)</a>:</h4>
<p>ah missed that detail.</p>



<a name="243944965"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243944965" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243944965">(Jun 25 2021 at 17:18)</a>:</h4>
<p>Cancelling DMA operations is asynchronous, or can it be done synchronous?</p>



<a name="243945012"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243945012" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243945012">(Jun 25 2021 at 17:18)</a>:</h4>
<p>If it's async - yes, the problem is fundamentally the same as with all other completion based APIs</p>



<a name="243948327"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243948327" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243948327">(Jun 25 2021 at 17:48)</a>:</h4>
<p>It usually doesn't take too much, so you probably can still do it blocking</p>



<a name="243952890"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243952890" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243952890">(Jun 25 2021 at 18:27)</a>:</h4>
<p>So on what you can do today:</p>
<ul>
<li>Do synchronous cancellation (which might block the foreground task more than necessary?)</li>
<li>Start an async cancellation, but let the task continue to run. Then only when the resource is accessed next time wait for it to get free (e.g. using an async mutex or semaphore)</li>
</ul>



<a name="243953207"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243953207" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243953207">(Jun 25 2021 at 18:30)</a>:</h4>
<p>The problem is that I can't cancel if the user forgets the future/transfer</p>



<a name="243953283"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243953283" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243953283">(Jun 25 2021 at 18:30)</a>:</h4>
<p>For the future:</p>
<ul>
<li>There had been a proposal about offering run-to-completion async fns,  which could model that <a href="#narrow/stream/187312-wg-async-foundations/topic/run.20to.20completion.20async.20fn">https://rust-lang.zulipchat.com/#narrow/stream/187312-wg-async-foundations/topic/run.20to.20completion.20async.20fn</a></li>
<li>Also mentioned in Carl's latest blog post: <a href="https://carllerche.com/2021/06/17/six-ways-to-make-async-rust-easier/">https://carllerche.com/2021/06/17/six-ways-to-make-async-rust-easier/</a></li>
</ul>



<a name="243953295"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243953295" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243953295">(Jun 25 2021 at 18:31)</a>:</h4>
<p>And if they do, they clear the borrow on the buffer and can use it at the same time as the DMA, they can even pop the stack of the buffer...</p>



<a name="243953361"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243953361" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthias247 <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243953361">(Jun 25 2021 at 18:31)</a>:</h4>
<blockquote>
<p>The problem is that I can't cancel if the user forgets the future/transfer</p>
</blockquote>
<p>It shouldn't matter. Even if the user forgets it, the task would still complete, and the completion should release the resource?</p>



<a name="243953461"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243953461" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243953461">(Jun 25 2021 at 18:32)</a>:</h4>
<p>The problem is that I can't use alloc</p>



<a name="243953557"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243953557" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243953557">(Jun 25 2021 at 18:33)</a>:</h4>
<p>The user controls the resource, the future only borrows it</p>



<a name="243959432"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243959432" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nagisa <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243959432">(Jun 25 2021 at 19:25)</a>:</h4>
<p>Yeah, that's the detail thats super easy to miss unfortunately. The only ideas I have are around some sort of a flag inside a buffer type itself, that knows that buffer is being used for DMA.</p>



<a name="243959584"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243959584" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> nagisa <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243959584">(Jun 25 2021 at 19:26)</a>:</h4>
<p>that way if the buffer is used after future is forgotten, you can panic or something; and if it is dropped (i.e. released) you can still cancel the DMA operation in the buffer's drop.</p>



<a name="243959701"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243959701" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243959701">(Jun 25 2021 at 19:27)</a>:</h4>
<p><span class="user-mention" data-user-id="123586">@nagisa</span> yeah, I thought about that too, but one would need some fn pointer or something inside this const generic buffer wrapper, to be able to stop the DMA, and worse, you would need to pin it</p>



<a name="243959883"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243959883" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243959883">(Jun 25 2021 at 19:28)</a>:</h4>
<p>Panic might also be a solution, like a Drop bomb with an unsafe disarm, but having to pin the buffer itself is awful</p>



<a name="243959969"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/187312-wg-async-foundations/topic/mem%3A%3Aforget%2C%20borrowed%20buffers%20and%20DMA/near/243959969" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thales Fragoso <a href="https://rust-lang.github.io/zulip_archive/stream/187312-wg-async-foundations/topic/mem.3A.3Aforget.2C.20borrowed.20buffers.20and.20DMA.html#243959969">(Jun 25 2021 at 19:29)</a>:</h4>
<p>It would also probably incur full GAT if used inside traits</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>